package org.iteasy.framework.utils;

import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;

import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Created by bo.chen on 2020/04/29 17:21:00
 */
public class CollectionUtils {

    /**
     * 从集合中获取
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> T getOne(List<T> list, Predicate<T> predicate) {
        if (null == list || 0 == list.size()) {
            return null;
        }
        list = list.stream().filter(predicate).collect(Collectors.toList());
        if (null == list || 0 == list.size()) {
            return null;
        }
        if (list.size() > 1) {
            throw new RuntimeException("结果中存在多条记录");
        }
        return list.get(0);
    }

    /**
     * 从集合中 过滤数据
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        if (null == list || 0 == list.size()) {
            return Collections.emptyList();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 判断集合为空
     * @param list
     * @return
     */
    public static boolean isEmpty(List<?> list) {
        return null == list || 0 == list.size();
    }

    /**
     * 判断集合不为空
     * @param list
     * @return
     */
    public static boolean isNotEmpty(List<?> list) {
        return !isEmpty(list);
    }

    /**
     * copy指定的字段
     * @param <T>
     * @param source
     * @param target
     * @return
     */
    public static <T> void copyProperties(Object source, T target) {
        BeanCopier copier = BeanCopier.create(source.getClass(), target.getClass(), false);
        copier.copy(source, target, null);
    }

    /**
     * copy指定的字段
     * @param <T>
     * @param source
     * @param target
     * @param fieldName
     * @return
     */
    public static <T> T copyPropertiesInclude(Object source, T target, String... fieldName) {
        BeanMap sourceBeanMap = BeanMap.create(source);
        BeanMap targetBeanMap = BeanMap.create(target);
        for (String field : fieldName) {
            targetBeanMap.put(field, sourceBeanMap.get(field));
        }
        return target;
    }

    /**
     * 集合对象
     * @param source
     * @param targetClass
     * @param biConsumer
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S,T> T copyProperties(S source, Class<T> targetClass, BiConsumer<S,T> biConsumer) {
        BeanCopier copier = BeanCopier.create(source.getClass(), targetClass, false);
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            copier.copy(source, target, null);
            if (null == biConsumer) {
                return target;
            }
            biConsumer.accept(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 集合对象
     * @param source
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S,T> T copyProperties(S source, Class<T> targetClass) {
        return copyProperties(source,targetClass, null);
    }

    /**
     * copy集合
     * @param source
     * @param targetClass
     * @param biConsumer
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S,T> List<T> copyList(List<S> source, Class<T> targetClass, BiConsumer<S,T> biConsumer) {
        if (isEmpty(source)) {
            return Collections.emptyList();
        }
        return source.stream().map(s -> copyProperties(s,targetClass,biConsumer)).collect(Collectors.toList());
    }

    /**
     * 复制集合
     * @param source
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S,T> List<T> copyList(List<S> source, Class<T> targetClass) {
        if (isEmpty(source)) {
            return Collections.emptyList();
        }
        return source.stream().map(s -> copyProperties(s, targetClass)).collect(Collectors.toList());
    }
}
